
#include "Command.h"
#include "CommandDescriptor.h"

CommandSp Command::Create(CommandDescriptorSp cd, string commandArgs)
{
	return Create(cd, commandArgs, SValueSpMapSp( new SValueSpMap() ) );
}

CommandSp Command::Create( CommandDescriptorSp cd, string commandArgs, SValueSpMapSp implicitArgs)
{
	return Create(cd, commandArgs, implicitArgs, SValueSpMapSp(new SValueSpMap()));
}

CommandSp Command::Create( CommandDescriptorSp cd, string commandArgs, SValueSpMapSp implicitArgs, SValueSpMapSp vars)
{
	if ( !cd )
	{
		throw SArgumentException("The command descriptor cannot be null.");
	}

	// Resolve expression in the command args
	
	// Build the struct
	commandArgs  = "{ " + commandArgs + " }";

	// Build a struct type descriptor to define inputs parameters
	SStructTypeDescriptorSp inputsTypeDescriptor = cd->GetInputsTypeDescriptor();

	// Build a struct type descriptor to define outputs parameters
	SStructTypeDescriptorSp outputsTypeDescriptor = cd->GetOutputsTypeDescriptor();

	// Build the struct of the inputs

	SStructSp inputs;

	try
	{
		inputs = SStruct::Parse( inputsTypeDescriptor, commandArgs, vars );
	}
	catch(...)
	{
		throw SArgumentException("Syntax error in the input arguments list.");
	}

	// If there are implicit variables add them to the struct of the inputs
	BOOST_FOREACH( SValueSpMapPair elem, *implicitArgs)
	{
		string varName = elem.first;
		
		if ( inputsTypeDescriptor->IsDefined(varName) && !inputs->IsSet(varName) )
		{
			SValueSp var = (*implicitArgs)[varName];

			inputs->Set(varName, var);
		}
	}

	// Check if the number of input is correct
	if ( !inputs->IsAllMemberSet() )
	{
		throw SArgumentException("The number of input is incorrect.");
	}

	// Build the empty struct of the outputs
	SStructSp outputs;

	try
	{
		outputs = SStruct::Create( outputsTypeDescriptor );
	}
	catch(...)
	{
		throw SArgumentException("Syntax error in the output arguments list.");
	}


	// Returns the istance of the command
	return CommandSp( new Command(cd, inputs, outputs) );
}
